<template>
  <div>
    <div class="root">
      <div style="position: absolute;top:100px;right:200px;z-index: 99">
        <el-button @click="getData">saveData</el-button>
        <el-button @click="clearData">clearData</el-button>
        <el-button @click="changeModel">changeModel</el-button>
      </div>
      <div class="node-panel">
        <img
          src="@/assets/g6/1.jpg"
          @dragstart="dragstart"
        >
        <img
          src="@/assets/g6/2.jpg"
          @dragstart="dragstart"
        >
      </div>
      <div id="graph" />
      <div
        v-if="img.src"
        id="image-edit"
        :style="{
          width: `${img.width}px`,
          height: `${img.height}px`,
          top: `${img.top}px`,
          left: `${img.left}px`,
        }"
      >
        <img :src="img.src">
        <i
          class="img-editor-bar bar-top"
          @mousedown="dragstartbar"
          @mousemove="(e)=>{dragbar(e,'top')}"
          @mouseup="dragendbar"
        />
        <i
          class="img-editor-bar bar-left"
          @mousedown="dragstartbar"
          @mousemove="(e)=>{dragbar(e,'left')}"
          @mouseup="dragendbar"
        />
        <i
          class="img-editor-bar bar-right"
          @mousedown="dragstartbar"
          @mousemove="(e)=>{dragbar(e,'right')}"
          @mouseup="dragendbar"
        />
        <i
          class="img-editor-bar bar-bottom"
          @mousedown="dragstartbar"
          @mousemove="(e)=>{dragbar(e,'bottom')}"
          @mouseup="dragendbar"
        />
        <div style="display: flex;width:180px;">
          <div
            class="btn confirm"
            @click="confirm"
          >
            确定
          </div>
          <div
            class="btn cancel"
            @click="handelCancel"
          >
            取消
          </div>
        </div>
      </div>
    </div>
    <el-dialog
      title="提示"
      :visible.sync="drawer"
      width="30%"
      :before-close="handleClose"
    >
      <el-form ref="form" :model="form" label-width="80px">
        <el-form-item label="宽" prop="width">
          <el-input v-model="form.width" />
        </el-form-item>
        <el-form-item label="高" prop="height">
          <el-input v-model="form.height" />
        </el-form-item>
        <el-form-item label="旋转角度" prop="rotate">
          <el-input v-model="form.rotate" />
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button type="primary" @click="onSubmit">提交</el-button>
        <el-button @click="handleClose">取消</el-button>
      </span>
    </el-dialog>
    <!--不同样式-->
    <!--        <el-drawer
      title="配置项"
      :visible.sync="drawer"
      direction="rtl"
      :before-close="handleClose"
    >
      <el-form ref="form" :model="form" label-width="80px">
        <el-form-item label="宽" prop="width">
          <el-input v-model="form.width" />
        </el-form-item>
        <el-form-item label="高" prop="height">
          <el-input v-model="form.height" />
        </el-form-item>
        <el-form-item label="旋转角度" prop="rotate">
          <el-input v-model="form.rotate" />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="onSubmit">提交</el-button>
          <el-button @click="handleClose">取消</el-button>
        </el-form-item>
      </el-form>
    </el-drawer>-->
  </div>
</template>

<script>
import G6 from '@antv/g6'
import registerNode from './node/registerNode'
import register from './exports.js'
// 锚点坐标
const anchorPointMap = [
  [0, 0.5],
  [0.5, 0],
  [1, 0.5],
  [0.5, 1]
]
export default {
  data() {
    return {
      drawer: false,
      form: {
        width: 0,
        height: 0
      },
      graph: null,
      img: {
        src: '',
        width: 0,
        height: 0,
        top: 0,
        left: 0,
        scale: 1
      },
      dragmode: false,
      offset: {
        x: 0,
        y: 0
      },
      canvasOffset: {
        x: 0,
        y: 0
      },
      headVisible: false,
      configVisible: false,
      config: '',
      tooltip: '',
      top: 0,
      left: 0,
      currentNodeId: '',
      edgeList: {},
      edit: false

    }
  },
  mounted() {
    // 创建画布
    this.$nextTick(() => {
      // registerNode(G6)
      register(G6)
      this.createGraphic()
    })
  },
  beforeDestroy() {
    this.graph.destroy()
  },
  methods: {
    changeModel() {
      console.log(this.graph.getGroup())
      /* this.edit = !this.edit
      const mode = this.edit ? 'edit' : 'default'
      this.graph.setMode(mode)*/
    },
    handleClose() {
      this.drawer = false
    },
    onSubmit() {
      const { width, height, rotate } = this.form
      if (rotate > 360 || rotate < -360) {
        this.$message.info('只能输入正负360度')
        return
      }
      const node = this.graph.findById(this.currentNodeId)

      const model = node.getModel()
      const src = model.baseUrl
      this.graph.removeItem(node)
      // 更新节点
      setTimeout(() => {
        this.addNode(JSON.stringify({
          src,
          width: Number(width),
          height: Number(height),
          exitId: this.currentNodeId,
          rotate: rotate || 0
        }), {
          x: Number(model.x),
          y: Number(model.y)
        })
      })
      this.updateEdgeStyle()
    },
    updateEdgeStyle() {
      setTimeout(() => {
        this.drawer = false
        // 找到连线node
        const edges = this.edgeList[this.currentNodeId]
        if (edges && edges.length > 0) {
          edges.forEach(addEdge => {
            this.graph.addItem('edge', addEdge)
          })
        } else {
          // 寻找是否有作为target 的对象
          let targetEdges = []
          for (const attr in this.edgeList) {
            const edges = this.edgeList[attr]
            if (edges && edges.length) {
              const edgesArr = edges.filter(item => item.target === this.currentNodeId)
              targetEdges = edgesArr && edgesArr.length ? targetEdges.concat(edgesArr) : targetEdges
            }
          }
          if (targetEdges.length) {
            targetEdges.forEach(targetEdge => {
              this.graph.addItem('edge', targetEdge)
            })
          }
        }
      }, 100)
    },
    clearData() {
      localStorage.removeItem('graph')
    },
    getData() {
      console.log(this.graph.save())
      const data = this.graph.save()
      if (data) {
        // const groups = this.graph.getNode()
        localStorage.setItem('graph', JSON.stringify(data))
      }
    },
    createGraphic() {
      const vm = this
      const menu = new G6.Menu({
        itemTypes: ['node'],
        getContent(e) {
          return `<p command="editLayer">编辑图层</p>
            <p command="toFront">置于顶层</p>
            <p command="toBack">置于底层</p>
            <p command="toDel">删除节点</p>
          `
        },
        handleMenuClick(target, item) {
          const command = target.getAttribute('command')
          vm[command](item)
        }
      })

      const grid = new G6.Grid()
      const graph = new G6.Graph({
        container: document.getElementById('graph'),
        width: window.innerWidth - 40,
        height: window.innerHeight - 40,
        defaultNode: {
          type: 'base-node-image'
        },
        defaultEdge: {
          type: 'hvh-edge'
        },
        // 覆盖全局样式
        nodeStateStyles: {
          'nodeState:default': {
            opacity: 1
          },
          'nodeState:hover': {
            opacity: 0.8
          },
          'nodeState:selected': {
            opacity: 0.9
          }
        },
        // 默认边不同状态下的样式集合
        edgeStateStyles: {
          'edgeState:default': {
            stroke: '#aab7c3'
          },
          'edgeState:selected': {
            stroke: '#1890FF'
          },
          'edgeState:hover': {
            stroke: '#1890FF',
            animate: true
          }
        },
        layout: {
          type: 'xxx'
        },
        modes: {
          default: [
            'drag-node', 'drag-canvas', 'drag-base-node', 'drag-base-edge'], //, 'drag-base-edge'
          edit: ['click-select']
        },
        plugins: [grid, menu]
      })

      this.graph = graph

      setTimeout(() => {
        let data = localStorage.getItem('graph')
        if (data) {
          data = JSON.parse(data)
          this.graph.read(data)
        }
      }, 1000)
      this.bindEvents()
    },
    dragstart(event) {
      const { src, naturalWidth, naturalHeight } = event.target

      this.img.scale = naturalWidth / naturalHeight
      event.dataTransfer.setData('img', JSON.stringify({
        src,
        width: naturalWidth,
        height: naturalHeight
      }))
    },
    bindEvents() {
      this.graph.on('drop', event => {
        const { clientX, clientY, originalEvent: { dataTransfer }} = event
        event.stopPropagation()
        if (dataTransfer) {
          const data = dataTransfer.getData('img')
          const { width, height } = JSON.parse(data)
          if (data) {
            dataTransfer.clearData()
            this.addNode(data, {
              x: clientX - 310,
              y: clientY - 50
            })
            this.img.top = clientY - 50 - height / 2
            this.img.left = clientX - 310 + width
          }
        }
      })

      this.graph.on('on-canvas-dragend', e => {
        this.canvasOffset.x = e.dx
        this.canvasOffset.y = e.dy
      })

      this.graph.on('on-node-mouseenter', e => {
        if (e && e.item) {
          // const model = e.item.get('model');

          // model.style.fill = 'rgba(24, 144, 255, .3)';
        }
      })

      this.graph.on('after-node-selected', e => {
        this.configVisible = !!e

        if (e && e.item) {
          const model = e.item.get('model')

          this.config = model
          this.label = model.label
          this.labelCfg = {
            fill: model.labelCfg.fill,
            fontSize: model.labelCfg.fontSize
          }
          this.node = {
            fill: model.style.fill,
            borderColor: model.style.stroke,
            lineDash: model.style.lineDash || 'none',
            width: model.style.width,
            height: model.style.height,
            shape: model.type
          }

          // model.label = e.item.get('id');
          /* this.graph.updateItem(e.item, {
            x: 100,
            y: 100,
          }); */
        }
      })

      this.graph.on('after-edge-selected', e => {
        this.configVisible = !!e

        if (e && e.item) {
          this.config = e.item.get('model').id

          this.graph.updateItem(e.item, {
            // shape: 'line-edge',
            style: {
              radius: 10,
              lineWidth: 2
            }
          })
        }
      })

      this.graph.on('on-edge-mousemove', e => {
        if (e && e.item) {
          this.tooltip = e.item.get('model').label
          this.left = e.clientX + 40
          this.top = e.clientY - 20
        }
      })

      this.graph.on('on-node-mousemove', e => {
        if (e && e.item) {
          this.tooltip = e.item.get('model').id
          this.left = e.clientX + 40
          this.top = e.clientY - 20
        }
      })

      this.graph.on('on-node-mouseleave', e => {
        if (e && e.item) {
          this.tooltip = ''
        }
      })

      this.graph.on('on-edge-mouseleave', e => {
        if (e && e.item) {
          this.tooltip = ''
        }
      })

      this.graph.on('before-node-removed', ({ target, callback }) => {
        console.log(target)
        setTimeout(() => {
          // 确认提示
          callback(true)
        }, 1000)
      })

      this.graph.on('after-node-dblclick', e => {
        if (e && e.item) {
          console.log(e.item)
        }
      })

      this.graph.on('on-node-click', e => {
        this.drawer = true
        const model = e.item.getModel()
        console.log(e, e.item, e.item.getModel())
        this.currentNodeId = model.id
        this.form.width = model.style.width || 0
        this.form.height = model.style.height || 0

        // console.log(e)
      })

      this.graph.on('before-edge-add', ({ source, target, type, sourceAnchor, targetAnchor }) => {
        setTimeout(() => {
          const addEdge = {
            source: source.get('id'),
            target: target.get('id'),
            sourceAnchor,
            targetAnchor,
            type: type || 'hvh-edge'
          }
          const edges = this.edgeList[source.get('id')]
          /* const targetEdges = this.edgeList[target.get('id')]*/
          if (edges && edges.length) {
            const exit = edges.filter(item => item.target === target.get('id'))
            if (exit.length === 0) {
              this.edgeList[source.get('id')].push(addEdge)
            }
          } else {
            this.edgeList[source.get('id')] = []
            this.edgeList[source.get('id')].push(addEdge)
          }
          /* if (targetEdges && targetEdges.length) {
            const exit = targetEdges.filter(item => item.target === source.get('id'))
            if (exit.length === 0) {
              this.edgeList[target.get('id')].push(addEdge)
            }
          } else {
            this.edgeList[target.get('id')] = []
            this.edgeList[target.get('id')].push(addEdge)
          }*/
          // localStorage.setItem('edgelist', JSON.stringify(this.edgeList))
          this.graph.addItem('edge', addEdge)
        }, 100)
      })

      this.graph.on('on-node-mousedown', e => {
        console.log('鼠标按下======1212====================')
      })
    },
    // 添加节点
    addNode(data, location) {
      const { src, width, height, exitId, rotate } = JSON.parse(data)
      const rotateRate = (Number(rotate) / 360) * (2 * Math.PI)
      const model = {
        x: location.x,
        y: location.y,
        type: 'base-node-image',
        style: {
          width,
          height,
          strokeOpacity: 0
        },
        baseUrl: src,
        exitId: exitId,
        rotate: rotateRate,
        name: 'nodeImg'
      }
      if (exitId) {
        model.id = exitId
      }
      // console.log(model)
      this.graph.addItem('node', model)
    },
    toFront(item) {
      item.toFront()
    },
    toBack(item) {
      item.toBack()
    },
    toDel(item) {
      this.graph.removeItem(item)
    },
    editLayer(item) {
      const model = item.getModel()
      const group = item.getContainer()
      const img = group.get('children').find(child => child.cfg.name === 'node-img')
      const rotate = group.get('children').find(child => child.cfg.name === 'shapeControlRotate')
      this.currentNodeId = model.id

      if (img) {
        const { img: image, width, height } = img.attrs
        this.img.src = image.src
        this.img.width = width
        this.img.height = height
        this.img.top = model.y - height / 2
        this.img.left = model.x - width / 2 + 100
      }

      img.hide()
      rotate && rotate.attr({
        opacity: 0
      })
      // rotate && rotate.hide()
      item.hide()

      console.log(group)
      // item.setState('rotateShow', false) // 二值状态
    },

    clearRotate() {
      const nodes = this.graph.getNodes()
      if (nodes && nodes.length) {
        nodes.forEach(node => {
          node.setState('rotateShow', false) // 二值状态
          /* const group = node.getContainer()
          const rotate = group.get('children').find(child => child.cfg.name === 'shapeControlRotate')
          console.log(rotate)
          rotate && rotate.remove()*/
        })
      }
    },
    dragstartbar(event) {
      this.dragmode = true
      this.offset.x = event.clientX
      this.offset.y = event.clientY
    },
    dragbar(event, tag) {
      console.log(tag)
      if (this.dragmode) {
        const distance = {
          x: 0,
          y: 0
        }
        distance.x = tag === 'left' ? -(event.clientX - this.offset.x) : event.clientX - this.offset.x
        distance.y = tag === 'top' ? -(event.clientY - this.offset.y) : event.clientY - this.offset.y

        this.offset.x = event.clientX
        this.offset.y = event.clientY

        if (tag === 'left' || tag === 'right') {
          this.img.width += distance.x * 2
          if (distance.y === 0) {
            // 重新计算图片高度
            this.img.height += distance.x * 2 / this.img.scale
            this.img.top -= distance.x / this.img.scale
          } else {
            this.img.height += distance.y * 2
            this.img.top -= distance.y
          }
          this.img.left -= distance.x
        } else {
          this.img.height += distance.y * 2
          if (distance.x === 0) {
            this.img.width += distance.y * 2 / this.img.scale
            this.img.left -= distance.y / this.img.scale
          } else {
            this.img.width += distance.x * 2
            this.img.left -= distance.x
          }

          this.img.top -= distance.y
        }
      }
    },
    dragendbar() {
      this.dragmode = false
    },
    handelCancel() {
      const node = this.graph.findById(this.currentNodeId)
      const group = node.getContainer()
      const img = group.get('children').find(child => child.cfg.name === 'node-img')
      img.show()
      node.show()
      this.img.src = ''
    },
    confirm() {
      const { width, height } = this.img
      const node = this.graph.findById(this.currentNodeId)

      const model = node.getModel()
      const src = model.baseUrl
      this.graph.removeItem(node)

      // 更新节点
      setTimeout(() => {
        this.addNode(JSON.stringify({
          src,
          width: Number(width),
          height: Number(height),
          exitId: this.currentNodeId
          // rotate: rotate || 0
        }), {
          x: Number(model.x),
          y: Number(model.y)
        })
      })
      this.updateEdgeStyle()
      this.img.src = ''
      /* const node = this.graph.findById(this.currentNodeId)
      const group = node.getContainer()
      const item = group.getFirst()
      const img = group.get('children').find(child => child.cfg.name === 'node-img')
      const { width, height } = this.img
      const model = {
        width,
        height,
        x: -width / 2,
        y: -height / 2
      }

      item.attr(model)
      img.attr({
        ...model,
        size:[width,height]
      })
      // this.graph.showItem(node)
      node.show()
      this.img.src = ''

      this.graph.refresh()*/
    }
  }
}
</script>

<style lang="scss">
.node-panel{
  width: 100px;
  position: absolute;
  top:0;
  left:0;
  height:100%;
  padding: 20px;
  background: #ccc;
  img{
    margin-bottom: 20px;
    cursor: move;
  }
}
#graph{margin-left: 100px;background: #fff}
.g6-component-contextmenu{
  p{cursor: pointer;}
}
#image-edit{
  position: absolute;
  width: 100px;
  height: 100px;
  top:100px;
  left:100px;
  opacity: 1;
  z-index: 2;
  border: 2px solid #6ccfff;
  background:#f1f1f1;
  user-select: none;
  cursor: move;
  img{
    display: block;
    width: 100%;
    height: auto;
  }
  .img-editor-bar{
    position: absolute;
    background: #fff;
    border-radius: 2px;
    box-shadow: 0 0 2px rgba(0,0,0,.3);
    &:before{
      content: '';
      display: block;
      width: 50px;
      height: 50px;
      margin-left: -25px;
      margin-top: -25px;
    }
  }
  .bar-top,
  .bar-bottom{
    height:4px;
    width: 20px;
    left: 50%;
    margin-left: -10px;
    cursor: ns-resize;
  }
  .bar-top{top:-2px;}
  .bar-bottom{bottom:-2px;}
  .bar-left,
  .bar-right{
    width:4px;
    height: 20px;
    top: 50%;
    margin-top: -10px;
    cursor: ew-resize;
  }
  .bar-left{left:-2px;}
  .bar-right{right:-2px;}
  .btn{
    width: 60px;
    height:25px;
    line-height:25px;
    cursor: pointer;
    margin-top: 20px;
    margin-left: 10px;
    color:#fff;
    border-radius: 4px;
    float: right;
    font-size: 12px;
    text-align: center;
  }
  .confirm{background: #409eff;}
  .cancel{color: #fff;background: #ccc}
}
</style>
